﻿using System.Collections;
using System.IO;
using System.Web.Caching;
using System.Web.Hosting;
using HTB.DevFx.Utils;

namespace HTB.DevFx.Security.Web
{
	public class FxVirtualPathProvider : VirtualPathProvider
	{
		public static void RegisterToHostingEnvironment(bool registerEvenExists) {
			if(RegisteredInstance != null && !registerEvenExists) {
				return;
			}
			HostingEnvironment.RegisterVirtualPathProvider(new FxVirtualPathProvider());
		}

		protected FxVirtualPathProvider() {}

		protected override void Initialize() {
			base.Initialize();
			RegisteredInstance = this;
		}

		protected static FxVirtualPathProvider RegisteredInstance;

		public override bool FileExists(string virtualPath) {
			if (this.IsFxVirtualPath(virtualPath)) {
				return true;
			}
			return base.FileExists(virtualPath);
		}

		protected virtual bool IsFxVirtualPath(string virtualPath) {
			string url;
			return this.IsFxVirtualPath(virtualPath, out url);
		}

		protected virtual bool IsFxVirtualPath(string virtualPath, out string url) {
			url = WebHelper.MakeUrlRelative(virtualPath, HostingEnvironment.ApplicationVirtualPath);
			return FxVirtualFile.FileExists(url);
		}

		public override VirtualFile GetFile(string virtualPath) {
			string url;
			if(this.IsFxVirtualPath(virtualPath, out url)) {
				var path = HostingEnvironment.MapPath(virtualPath);
				if(!File.Exists(path)) {
					return new FxVirtualFile(virtualPath, url, this);
				}
			}
			return base.GetFile(virtualPath);
		}

		public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, System.DateTime utcStart) {
			return null;
		}
	}

	public class FxVirtualFile : VirtualFile
	{
		public FxVirtualFile(string virtualPath, string url, FxVirtualPathProvider provider) : base(virtualPath) {
			this.url = url;
			this.provider = provider;
		}

		protected string url;
		protected FxVirtualPathProvider provider;

		protected internal static bool FileExists(string url, out Stream fileStream) {
			fileStream = null;
			var appRoot = AppSetting.AppRoot;
			if(!appRoot.EndsWith("/")) {
				appRoot += "/";
			}
			if(!url.StartsWith(appRoot, true, null)) {
				return false;
			}

			url = url.Remove(0, appRoot.Length);		//remove AppRoot
			url = "/devfx/" + url;
			url = url.Replace('/', '.');
			var type = typeof(FxVirtualFile);
			var resName = type.Namespace + url;
			var assembly = type.Assembly;
			fileStream = assembly.GetManifestResourceStream(resName);
			return fileStream != null;
		}

		protected internal static bool FileExists(string url) {
			Stream fileStream;
			var exists = FileExists(url, out fileStream);
			if(fileStream != null) {
				fileStream.Dispose();
			}
			return exists;
		}

		public override Stream Open() {
			Stream fileStream;
			FileExists(this.url, out fileStream);
			return fileStream;
		}
	}
}
